package br.usp.ime.ingpos.services;

import java.io.File;
import java.io.IOException;
import java.util.Set;

import org.apache.commons.io.FileUtils;
import org.springframework.beans.BeanUtils;

import br.com.caelum.vraptor.interceptor.download.FileDownload;
import br.com.caelum.vraptor.ioc.Component;
import br.com.caelum.vraptor.ioc.RequestScoped;
import br.usp.ime.ingpos.modelo.Bolsa;
import br.usp.ime.ingpos.modelo.Candidato;
import br.usp.ime.ingpos.modelo.Curriculo;
import br.usp.ime.ingpos.modelo.DisciplinaEspecial;
import br.usp.ime.ingpos.modelo.FormacaoAcademica;
import br.usp.ime.ingpos.modelo.IniciacaoCientifica;
import br.usp.ime.ingpos.modelo.Usuario;
import br.usp.ime.ingpos.modelo.dao.BolsaDAO;
import br.usp.ime.ingpos.modelo.dao.CandidatoDAO;
import br.usp.ime.ingpos.modelo.dao.CurriculoDAO;
import br.usp.ime.ingpos.modelo.dao.DisciplinaEspecialDAO;
import br.usp.ime.ingpos.modelo.dao.FormacaoAcademicaDAO;
import br.usp.ime.ingpos.modelo.dao.IniciacaoCientificaDAO;
import br.usp.ime.ingpos.modelo.dao.UsuarioDao;
import br.usp.ime.ingpos.web.controllers.UsuarioSessao;

@RequestScoped
@Component
public class CurriculoService
{
    private CurriculoDAO curriculoDAO;
    private FormacaoAcademicaDAO formacaoAcademicaDAO;
    private IniciacaoCientificaDAO iniciacaoCientificaDAO;
    private UsuarioSessao usuarioSessao;
    private UsuarioDao usuarioDao;
    private CandidatoDAO candidatoDao;
    private BolsaDAO bolsaDAO;
    private DisciplinaEspecialDAO disciplinaEspecialDAO;

    public CurriculoService(
        final BolsaDAO bolsaDAO,
        final CandidatoDAO candidatoDao,
        final CurriculoDAO curriculoDAO,
        final FormacaoAcademicaDAO formacaoAcademicaDAO,
        final IniciacaoCientificaDAO iniciacaoCientificaDAO,
        final UsuarioDao usuarioDao,
        final UsuarioSessao usuarioSessao,
        final DisciplinaEspecialDAO disciplinaEspecialDAO )
    {
        this.curriculoDAO = curriculoDAO;
        this.candidatoDao = candidatoDao;
        this.usuarioSessao = usuarioSessao;
        this.formacaoAcademicaDAO = formacaoAcademicaDAO;
        this.iniciacaoCientificaDAO = iniciacaoCientificaDAO;
        this.usuarioDao = usuarioDao;
        this.bolsaDAO = bolsaDAO;
        this.disciplinaEspecialDAO = disciplinaEspecialDAO;
    }

    public Usuario getUsuarioAtual()
    {
        return usuarioDao.findById( usuarioSessao.getUsuario().getUsuarioID() );
    }

    public Curriculo getCurriculoUsuarioAtual()
    {
        final Usuario usuario = usuarioDao.findById( usuarioSessao.getUsuario().getUsuarioID() );
        return ((Candidato) usuario).getCurriculo();
    }

    public void atualizarCurriculo(
        final Curriculo curriculo )
    {
        final Curriculo curriculoPersistente = getCurriculoUsuarioAtual();

        BeanUtils.copyProperties( curriculo, curriculoPersistente, new String[] {
            "curriculoID",
            "formacoesAcademicas",
            "bolsas",
            "iniciacoesCientificas",
            "disciplinasEspeciais"
        } );

        curriculoDAO.saveOrUpdate( curriculoPersistente );
    }

    public void adicionaFormacaoAcademica(
        FormacaoAcademica formacaoAcademica )
    {
        if( formacaoAcademica.getFormacaoAcademicaId() == null ) {
            final Usuario usuario = usuarioDao.findById( usuarioSessao.getUsuario().getUsuarioID() );
            Candidato candidato = (Candidato) usuario;
            Curriculo curriculo = candidato.getCurriculo();

            if( curriculo == null ) {
                curriculo = new Curriculo();
                candidato.setCurriculo( curriculo );
            }

            curriculo.adicionaFormacaoAcademica( formacaoAcademica );
            candidatoDao.saveOrUpdate( candidato );
        } else {
            FormacaoAcademica formacaoPersistente = this.getFormacaoAcademicaParaEdicao( formacaoAcademica.getFormacaoAcademicaId() );
            BeanUtils.copyProperties( formacaoAcademica, formacaoPersistente, new String[] {
                "formacaoAcademicaId"
            } );
            formacaoAcademicaDAO.saveOrUpdate( formacaoPersistente );
        }

    }

    public FormacaoAcademica getFormacaoAcademicaParaEdicao(
        final Long formacaoAcademicaId )
    {
        final FormacaoAcademica formacaoAcademica;

        // Nova formacao
        if( formacaoAcademicaId == null ) {
            formacaoAcademica = new FormacaoAcademica();
        } else {
            final Curriculo curriculo = getCurriculoUsuarioAtual();
            final Set<FormacaoAcademica> formacoes = curriculo.getFormacoesAcademicas();
            formacaoAcademica = formacaoAcademicaDAO.procurarFormacaoAcademicaById( formacaoAcademicaId );
            if( formacoes.contains( formacaoAcademica ) )
                return formacaoAcademica;
            else
                return null;
        }
        return formacaoAcademica;
    }

    public void removerFormacaoAcademica(
        final Long formacaoAcademicaId )
    {
        final Usuario usuario = usuarioDao.findById( usuarioSessao.getUsuario().getUsuarioID() );
        final Candidato candidato = (Candidato) usuario;
        final Curriculo curriculo = candidato.getCurriculo();

        final FormacaoAcademica formacaoPersistente = this.getFormacaoAcademicaParaEdicao( formacaoAcademicaId );
        final Set<FormacaoAcademica> formacoes = curriculo.getFormacoesAcademicas();
        if( formacoes.contains( formacaoPersistente ) ) {
            curriculo.removeFormacaoAcademica( formacaoPersistente );
            candidatoDao.saveOrUpdate( candidato );
            formacaoAcademicaDAO.delete( formacaoPersistente );
        }
    }

    public IniciacaoCientifica getIniciacaoCientificaParaEdicao(
        final Long iniciacaoCientificaId )
    {
        final IniciacaoCientifica iniciacaoCientifica;

        // Nova Iniciacao
        if( iniciacaoCientificaId == null ) {
            iniciacaoCientifica = new IniciacaoCientifica();
        } else {
            final Curriculo curriculo = getCurriculoUsuarioAtual();
            final Set<IniciacaoCientifica> ics = curriculo.getIniciacoesCientificas();
            iniciacaoCientifica = iniciacaoCientificaDAO.procurarIniciacaoCientificaById( iniciacaoCientificaId );
            if( ics.contains( iniciacaoCientifica ) )
                return iniciacaoCientifica;
            else
                return null;

        }
        return iniciacaoCientifica;
    }

    public void removerIniciacaoCientifica(
        final Long iniciacaoCientificaId )
    {

        final Usuario usuario = usuarioDao.findById( usuarioSessao.getUsuario().getUsuarioID() );
        final Candidato candidato = (Candidato) usuario;
        final Curriculo curriculo = candidato.getCurriculo();

        Set<IniciacaoCientifica> iniciacoes = curriculo.getIniciacoesCientificas();
        final IniciacaoCientifica iniciacaoCientificaPersistente = this.getIniciacaoCientificaParaEdicao( iniciacaoCientificaId );
        if( iniciacoes.contains( iniciacaoCientificaPersistente ) ) {
            curriculo.removeIniciacaoCientifica( iniciacaoCientificaPersistente );
            candidatoDao.saveOrUpdate( candidato );
            iniciacaoCientificaDAO.delete( iniciacaoCientificaPersistente );
        }
    }

    public void adicionaIniciacaoCientifica(
        IniciacaoCientifica iniciacaoCientifica )
    {
        if( iniciacaoCientifica.getIniciacaoCientificaId() == null ) {
            final Usuario usuario = usuarioDao.findById( usuarioSessao.getUsuario().getUsuarioID() );
            Candidato candidato = (Candidato) usuario;
            Curriculo curriculo = candidato.getCurriculo();

            if( curriculo == null ) {
                curriculo = new Curriculo();
                candidato.setCurriculo( curriculo );
            }
            iniciacaoCientificaDAO.saveOrUpdate( iniciacaoCientifica );
            curriculo.adicionaIniciacaoCientifica( iniciacaoCientifica );
            curriculoDAO.saveOrUpdate( curriculo );
            candidatoDao.saveOrUpdate( candidato );
        } else {
            IniciacaoCientifica iniciacaoPersistente = this.getIniciacaoCientificaParaEdicao( iniciacaoCientifica.getIniciacaoCientificaId() );
            BeanUtils.copyProperties( iniciacaoCientifica, iniciacaoPersistente, new String[] {
                "iniciacaoCientificaId"
            } );
            iniciacaoCientificaDAO.saveOrUpdate( iniciacaoPersistente );
        }
    }

    public Bolsa getBolsaParaEdicao(
        Long bolsaId )
    {
        Bolsa bolsa = null;

        // Nova bolsa
        if( bolsaId == null ) {
            bolsa = new Bolsa();
        } else {
            final Curriculo curriculo = getCurriculoUsuarioAtual();
            Set<Bolsa> bolsas = curriculo.getBolsas();
            Bolsa bolsaPersistente = bolsaDAO.procurarBolsaById( bolsaId );
            if( bolsas.contains( bolsaPersistente ) ) {
                bolsa = bolsaPersistente;
            }
        }
        return bolsa;
    }

    public void removerBolsa(
        final Long bolsaId )
    {
        final Bolsa bolsaPersistente = this.getBolsaParaEdicao( bolsaId );
        final Usuario usuario = usuarioDao.findById( usuarioSessao.getUsuario().getUsuarioID() );
        final Candidato candidato = (Candidato) usuario;
        final Curriculo curriculo = candidato.getCurriculo();

        Bolsa bolsa = bolsaDAO.procurarBolsaById( bolsaId );
        Set<Bolsa> conjuntoBolsa = curriculo.getBolsas();
        if( conjuntoBolsa.contains( bolsa ) ) {
            curriculo.removeBolsa( bolsaPersistente );
            candidatoDao.saveOrUpdate( candidato );
        }

    }

    public void adicionaBolsa(
        Bolsa bolsa )
    {
        if( bolsa.getBolsaId() == null ) {
            final Usuario usuario = usuarioDao.findById( usuarioSessao.getUsuario().getUsuarioID() );
            Candidato candidato = (Candidato) usuario;
            Curriculo curriculo = candidato.getCurriculo();

            if( curriculo == null ) {
                curriculo = new Curriculo();
                candidato.setCurriculo( curriculo );
            }

            curriculo.adicionaBolsa( bolsa );
            candidatoDao.saveOrUpdate( candidato );
        } else {
            Bolsa bolsaPersistente = this.getBolsaParaEdicao( bolsa.getBolsaId() );
            BeanUtils.copyProperties( bolsa, bolsaPersistente, new String[] {
                "bolsaId"
            } );
            bolsaDAO.saveOrUpdate( bolsaPersistente );
        }

    }

    public void adicionarDisciplina(
        DisciplinaEspecial disciplinaEspecial )
    {
        final Usuario usuario = usuarioDao.findById( usuarioSessao.getUsuario().getUsuarioID() );
        Candidato candidato = (Candidato) usuario;
        Curriculo curriculo = candidato.getCurriculo();
        if( disciplinaEspecial.getDisciplinaEspecialID() == null ) {

            if( curriculo == null ) {
                curriculo = new Curriculo();
                candidato.setCurriculo( curriculo );
            }
            disciplinaEspecialDAO.saveOrUpdate( disciplinaEspecial );
            curriculo.adicionaDisciplinaEspecial( disciplinaEspecial );
            candidatoDao.saveOrUpdate( candidato );
        } else {
            DisciplinaEspecial disciplinaEspecialEditada = getDisciplinaParaEdicao( disciplinaEspecial.getDisciplinaEspecialID() );
            BeanUtils.copyProperties( disciplinaEspecial, disciplinaEspecialEditada, new String[] {
                "disciplinaEspecialID"
            } );
            disciplinaEspecialDAO.saveOrUpdate( disciplinaEspecialEditada );
        }
    }

    public void removerDisciplinaEspecial(
        Long disciplinaEspecialID )
    {
        Curriculo curriculo = getCurriculoUsuarioAtual();
        DisciplinaEspecial disciplinaEspecial = disciplinaEspecialDAO.procurarDisciplinaEspecialPorID( disciplinaEspecialID );
        Set<DisciplinaEspecial> conjuntoDeDisciplinas = curriculo.getDisciplinasEspeciais();
        if( conjuntoDeDisciplinas.contains( disciplinaEspecial ) ) {
            curriculo.removeDisciplinaEspecial( disciplinaEspecial );
        }
        curriculoDAO.saveOrUpdate( curriculo );
    }

    public DisciplinaEspecial getDisciplinaParaEdicao(
        Long disciplinaEspecialID )
    {

        DisciplinaEspecial disciplinaEspecial = null;
        Curriculo curriculo = getCurriculoUsuarioAtual();

        if( disciplinaEspecialID == null ) {
            disciplinaEspecial = new DisciplinaEspecial();
        } else {
            DisciplinaEspecial disciplina = disciplinaEspecialDAO.procurarDisciplinaEspecialPorID( disciplinaEspecialID );
            Set<DisciplinaEspecial> conjuntoDeDisciplinas = curriculo.getDisciplinasEspeciais();
            if( conjuntoDeDisciplinas.contains( disciplina ) ) {
                disciplinaEspecial = disciplina;
            }
        }
        return disciplinaEspecial;
    }

    public FileDownload getArquivoDiplomaPDF(
        final Usuario usuario )
    {
        final Curriculo curriculo = ((Candidato) usuario).getCurriculo();

        return carregarFileDownload( curriculo.getNomeArquivoDiploma(),
            curriculo.getArquivoDiplomaPDF() );
    }

    public FileDownload getArquivoHistoricoPDF(
        final Usuario usuario )
    {
        final Curriculo curriculo = ((Candidato) usuario).getCurriculo();

        return carregarFileDownload( curriculo.getNomeArquivoDiploma(),
            curriculo.getArquivoDiplomaPDF() );
    }

    public FileDownload getArquivoPosCompPDF(
        final Usuario usuario )
    {
        final Curriculo curriculo = ((Candidato) usuario).getCurriculo();

        return carregarFileDownload( curriculo.getNomeArquivoDiploma(),
            curriculo.getArquivoDiplomaPDF() );
    }

    public FileDownload getArquivoDiplomaMestradoPDF(
        final Usuario usuario )
    {
        final Curriculo curriculo = ((Candidato) usuario).getCurriculo();

        return carregarFileDownload( curriculo.getNomeArquivoDiplomaMestrado(),
            curriculo.getArquivoDiplomaMestradoPDF() );
    }
    
    public FileDownload getArquivoHistoricoMestradoPDF(
        final Usuario usuario )
    {
        final Curriculo curriculo = ((Candidato) usuario).getCurriculo();

        return carregarFileDownload( curriculo.getNomeArquivoHIstoricoMestrado(),
            curriculo.getArquivoHistoricoMestradoPDF() );
    }
    
    private FileDownload carregarFileDownload(
        final String nomeArquivo,
        final byte[] conteudoBytes )
    {
        if( nomeArquivo != null ) {
            final String contentType = "application/pdf";
            final StringBuilder fileName = new StringBuilder();

            fileName.append( nomeArquivo );
            fileName.append( ".pdf" );
            File file = new File( fileName.toString() );
            FileDownload fileDownloadCarregado = null;
            try {
                FileUtils.writeByteArrayToFile( file, conteudoBytes );
                fileDownloadCarregado = new FileDownload( file, contentType, fileName.toString() );
            } catch( IOException e ) {
                fileDownloadCarregado = null;
            }
            return fileDownloadCarregado;

        } else {
            return null;
        }

    }
    
    public boolean curriculoFinalizado(){
        Candidato candidato = candidatoDao.findById( usuarioSessao.getUsuarioId() );
        if(candidato.getCurriculo() == null)
            return false;
        if(candidato.getCurriculo().getFormacoesAcademicas() == null)
            return false;
        return true;
    }

}
